#!/usr/bin/env python3  # 指定Python3解释器路径，确保使用正确版本
# -*- coding: utf-8 -*-  # 设置文件编码为UTF-8，支持中文字符

import json  # 导入json模块，用于数据的序列化和反序列化
import os  # 导入os模块，用于操作系统相关功能如文件路径检查
import time  # 导入time模块，用于时间相关操作
from datetime import datetime  # 从datetime模块导入datetime类，用于日期时间处理
from typing import List, Dict, Optional  # 导入类型提示，增强代码可读性和IDE支持

class Student:  # 定义学生类，用于封装学生相关的属性和方法
    def __init__(self, student_id: str, name: str, class_name: str, major: str, phone: str = "", email: str = ""):  # 构造函数，初始化学生对象的属性
        self.student_id = student_id  # 存储学生学号，作为唯一标识符
        self.name = name  # 存储学生姓名
        self.class_name = class_name  # 存储学生所在班级
        self.major = major  # 存储学生专业信息
        self.phone = phone  # 存储学生电话号码，可选参数
        self.email = email  # 存储学生邮箱地址，可选参数
        self.create_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")  # 记录学生信息创建时间，格式化为字符串
    
    def to_dict(self) -> dict:  # 定义方法将学生对象转换为字典格式，便于序列化存储
        return {  # 返回包含所有学生属性的字典
            'student_id': self.student_id,  # 学号字段
            'name': self.name,  # 姓名字段
            'class_name': self.class_name,  # 班级字段
            'major': self.major,  # 专业字段
            'phone': self.phone,  # 电话字段
            'email': self.email,  # 邮箱字段
            'create_time': self.create_time  # 创建时间字段
        }
    
    @classmethod  # 类方法装饰器，表示这是一个类方法而不是实例方法
    def from_dict(cls, data: dict):  # 类方法，从字典数据创建学生对象
        student = cls(  # 调用类构造函数创建新的学生实例
            data['student_id'],  # 从字典获取学号
            data['name'],  # 从字典获取姓名
            data['class_name'],  # 从字典获取班级
            data['major'],  # 从字典获取专业
            data.get('phone', ''),  # 安全获取电话，不存在则使用空字符串
            data.get('email', '')  # 安全获取邮箱，不存在则使用空字符串
        )
        student.create_time = data.get('create_time', datetime.now().strftime("%Y-%m-%d %H:%M:%S"))  # 设置创建时间，如果不存在则使用当前时间
        return student  # 返回创建的学生对象
    
    def __str__(self) -> str:  # 定义字符串表示方法，用于打印和显示学生信息
        return f"学号：{self.student_id} | 姓名：{self.name} | 班级：{self.class_name} | 专业：{self.major}"  # 格式化返回学生基本信息字符串

class Award:  # 定义奖项类，用于封装奖项相关的属性和方法
    def __init__(self, award_id: str, name: str, level: str, description: str = "", score: int = 0):  # 构造函数，初始化奖项对象的属性
        self.award_id = award_id  # 存储奖项ID，作为唯一标识符
        self.name = name  # 存储奖项名称
        self.level = level  # 存储奖项级别（国家级、省级、校级、院级）
        self.description = description  # 存储奖项描述信息，可选参数
        self.score = score  # 存储奖项对应的分数，可选参数，默认为0
        self.create_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")  # 记录奖项信息创建时间，格式化为字符串
    
    def to_dict(self) -> dict:  # 定义方法将奖项对象转换为字典格式，便于序列化存储
        return {  # 返回包含所有奖项属性的字典
            'award_id': self.award_id,  # 奖项ID字段
            'name': self.name,  # 奖项名称字段
            'level': self.level,  # 奖项级别字段
            'description': self.description,  # 奖项描述字段
            'score': self.score,  # 奖项分数字段
            'create_time': self.create_time  # 创建时间字段
        }
    
    @classmethod  # 类方法装饰器，表示这是一个类方法而不是实例方法
    def from_dict(cls, data: dict):  # 类方法，从字典数据创建奖项对象
        award = cls(  # 调用类构造函数创建新的奖项实例
            data['award_id'],  # 从字典获取奖项ID
            data['name'],  # 从字典获取奖项名称
            data['level'],  # 从字典获取奖项级别
            data.get('description', ''),  # 安全获取描述，不存在则使用空字符串
            data.get('score', 0)  # 安全获取分数，不存在则使用0
        )
        award.create_time = data.get('create_time', datetime.now().strftime("%Y-%m-%d %H:%M:%S"))  # 设置创建时间，如果不存在则使用当前时间
        return award  # 返回创建的奖项对象
    
    def __str__(self) -> str:  # 定义字符串表示方法，用于打印和显示奖项信息
        return f"奖项ID：{self.award_id} | 名称：{self.name} | 级别：{self.level} | 分数：{self.score}"  # 格式化返回奖项基本信息字符串

class Evaluation:  # 定义评定类，用于封装评定记录相关的属性和方法
    def __init__(self, eval_id: str, student_id: str, award_id: str, eval_date: str, evaluator: str = "", remarks: str = ""):  # 构造函数，初始化评定对象的属性
        self.eval_id = eval_id  # 存储评定ID，作为唯一标识符
        self.student_id = student_id  # 存储关联的学生ID，建立学生与评定的关系
        self.award_id = award_id  # 存储关联的奖项ID，建立奖项与评定的关系
        self.eval_date = eval_date  # 存储评定日期
        self.evaluator = evaluator  # 存储评定人信息，可选参数
        self.remarks = remarks  # 存储评定备注信息，可选参数
        self.create_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")  # 记录评定信息创建时间，格式化为字符串
    
    def to_dict(self) -> dict:  # 定义方法将评定对象转换为字典格式，便于序列化存储
        return {  # 返回包含所有评定属性的字典
            'eval_id': self.eval_id,  # 评定ID字段
            'student_id': self.student_id,  # 学生ID字段
            'award_id': self.award_id,  # 奖项ID字段
            'eval_date': self.eval_date,  # 评定日期字段
            'evaluator': self.evaluator,  # 评定人字段
            'remarks': self.remarks,  # 备注字段
            'create_time': self.create_time  # 创建时间字段
        }
    
    @classmethod  # 类方法装饰器，表示这是一个类方法而不是实例方法
    def from_dict(cls, data: dict):  # 类方法，从字典数据创建评定对象
        evaluation = cls(  # 调用类构造函数创建新的评定实例
            data['eval_id'],  # 从字典获取评定ID
            data['student_id'],  # 从字典获取学生ID
            data['award_id'],  # 从字典获取奖项ID
            data['eval_date'],  # 从字典获取评定日期
            data.get('evaluator', ''),  # 安全获取评定人，不存在则使用空字符串
            data.get('remarks', '')  # 安全获取备注，不存在则使用空字符串
        )
        evaluation.create_time = data.get('create_time', datetime.now().strftime("%Y-%m-%d %H:%M:%S"))  # 设置创建时间，如果不存在则使用当前时间
        return evaluation  # 返回创建的评定对象
    
    def __str__(self) -> str:  # 定义字符串表示方法，用于打印和显示评定信息
        return f"评定ID：{self.eval_id} | 学生ID：{self.student_id} | 奖项ID：{self.award_id} | 评定日期：{self.eval_date}"  # 格式化返回评定基本信息字符串

class StudentAwardSystem:  # 定义学生奖评系统主类，包含系统的核心功能
    
    def __init__(self):  # 构造函数，初始化系统对象的属性
        self.students: Dict[str, Student] = {}  # 初始化学生字典，键为学号，值为学生对象
        self.awards: Dict[str, Award] = {}  # 初始化奖项字典，键为奖项ID，值为奖项对象
        self.evaluations: Dict[str, Evaluation] = {}  # 初始化评定字典，键为评定ID，值为评定对象
        self.data_file = "student_award_data.txt"  # 设置数据文件名，用于持久化存储
        self.load_data()  # 调用加载数据方法，从文件中恢复系统数据
    
    def save_data(self):  # 定义保存数据方法，将内存中的数据持久化到文件
        try:  # 使用try-except块处理可能出现的异常
            data = {  # 构建要保存的数据字典结构
                'students': {sid: student.to_dict() for sid, student in self.students.items()},  # 将所有学生对象转换为字典
                'awards': {aid: award.to_dict() for aid, award in self.awards.items()},  # 将所有奖项对象转换为字典
                'evaluations': {eid: evaluation.to_dict() for eid, evaluation in self.evaluations.items()}  # 将所有评定对象转换为字典
            }
            with open(self.data_file, 'w', encoding='utf-8') as f:  # 以写入模式打开文件，指定UTF-8编码
                json.dump(data, f, ensure_ascii=False, indent=2)  # 将数据序列化为JSON格式写入文件，ensure_ascii=False支持中文，indent=2格式化输出
            print("数据保存成功！")
        except Exception as e:  # 捕获所有异常
            print(f"数据保存失败：{e}")
    
    def load_data(self):  # 定义加载数据方法，从文件中读取数据到内存
        try:  # 使用try-except块处理可能出现的异常
            if os.path.exists(self.data_file):  # 检查数据文件是否存在
                with open(self.data_file, 'r', encoding='utf-8') as f:  # 以读取模式打开文件，指定UTF-8编码
                    data = json.load(f)  # 从文件中加载JSON数据并反序列化
                
                if 'students' in data:  # 检查数据中是否包含学生信息
                    for sid, student_data in data['students'].items():  # 遍历学生数据字典
                        self.students[sid] = Student.from_dict(student_data)  # 从字典创建学生对象并添加到系统中
                
                if 'awards' in data:  # 检查数据中是否包含奖项信息
                    for aid, award_data in data['awards'].items():  # 遍历奖项数据字典
                        self.awards[aid] = Award.from_dict(award_data)  # 从字典创建奖项对象并添加到系统中
                
                if 'evaluations' in data:  # 检查数据中是否包含评定信息
                    for eid, eval_data in data['evaluations'].items():  # 遍历评定数据字典
                        self.evaluations[eid] = Evaluation.from_dict(eval_data)  # 从字典创建评定对象并添加到系统中
                
                print("数据加载成功！")
        except Exception as e:  # 捕获所有异常
            print(f"数据加载失败：{e}")
    
    def add_student(self):  # 定义添加学生方法，处理新学生信息的录入
        print("\n=== 添加学生 ===")
        student_id = input("请输入学号：").strip()  # 获取用户输入的学号并去除首尾空格
        
        if student_id in self.students:  # 检查学号是否已经存在
            print("该学号已存在！")
            return  # 如果存在则退出方法
        
        name = input("请输入姓名：").strip()  # 获取用户输入的姓名并去除首尾空格
        class_name = input("请输入班级：").strip()  # 获取用户输入的班级并去除首尾空格
        major = input("请输入专业：").strip()  # 获取用户输入的专业并去除首尾空格
        phone = input("请输入电话（可选）：").strip()  # 获取用户输入的电话号码，可选项
        email = input("请输入邮箱（可选）：").strip()  # 获取用户输入的邮箱地址，可选项
        
        if not all([student_id, name, class_name, major]):  # 检查必填字段是否都有值
            print("学号、姓名、班级、专业不能为空！")
            return  # 如果有空值则退出方法
        
        student = Student(student_id, name, class_name, major, phone, email)  # 创建新的学生对象
        self.students[student_id] = student  # 将学生对象添加到系统的学生字典中
        print(f"学生 {name} 添加成功！")
        self.save_data()  # 保存数据到文件
    
    def delete_student(self):  # 定义删除学生方法，处理学生信息的删除
        print("\n=== 删除学生 ===")
        student_id = input("请输入要删除的学号：").strip()  # 获取用户输入的要删除的学号
        
        if student_id not in self.students:  # 检查学号是否存在
            print("学号不存在！")
            return  # 如果不存在则退出方法
        
        student = self.students[student_id]  # 获取要删除的学生对象
        confirm = input(f"确认删除学生 {student.name}（{student_id}）？(y/n)：").strip().lower()  # 请求用户确认删除操作
        
        if confirm == 'y':  # 如果用户确认删除
            to_delete = [eid for eid, evaluation in self.evaluations.items() if evaluation.student_id == student_id]  # 找出所有与该学生相关的评定记录
            for eid in to_delete:  # 遍历要删除的评定ID列表
                del self.evaluations[eid]  # 删除相关的评定记录，保持数据一致性
            
            del self.students[student_id]  # 从学生字典中删除该学生
            print(f"学生 {student.name} 删除成功！")
            self.save_data()  # 保存数据到文件
        else:  # 如果用户取消删除
            print("取消删除。")
    
    def update_student(self):  # 定义修改学生信息方法，处理学生信息的更新
        print("\n=== 修改学生信息 ===")
        student_id = input("请输入要修改的学号：").strip()  # 获取用户输入的要修改的学号
        
        if student_id not in self.students:  # 检查学号是否存在
            print("学号不存在！")
            return  # 如果不存在则退出方法
        
        student = self.students[student_id]  # 获取要修改的学生对象
        print(f"当前学生信息：{student}")
        
        print("\n请输入新信息（直接回车保持原值）：")
        name = input(f"姓名（{student.name}）：").strip()  # 获取新的姓名，如果为空则保持原值
        class_name = input(f"班级（{student.class_name}）：").strip()  # 获取新的班级，如果为空则保持原值
        major = input(f"专业（{student.major}）：").strip()  # 获取新的专业，如果为空则保持原值
        phone = input(f"电话（{student.phone}）：").strip()  # 获取新的电话，如果为空则保持原值
        email = input(f"邮箱（{student.email}）：").strip()  # 获取新的邮箱，如果为空则保持原值
        
        if name:  # 如果输入了新的姓名
            student.name = name  # 更新学生姓名
        if class_name:  # 如果输入了新的班级
            student.class_name = class_name  # 更新学生班级
        if major:  # 如果输入了新的专业
            student.major = major  # 更新学生专业
        if phone:  # 如果输入了新的电话
            student.phone = phone  # 更新学生电话
        if email:  # 如果输入了新的邮箱
            student.email = email  # 更新学生邮箱
        
        print("学生信息修改成功！")
        self.save_data()  # 保存数据到文件
    
    def search_student(self):  # 定义查询学生方法，提供多种查询方式
        print("\n=== 查询学生 ===")
        print("1. 按学号查询")
        print("2. 按姓名查询")
        print("3. 按班级查询")
        print("4. 按专业查询")
        
        choice = input("请选择查询方式：").strip()  # 获取用户选择的查询方式
        
        if choice == '1':  # 如果选择按学号查询
            student_id = input("请输入学号：").strip()  # 获取要查询的学号
            if student_id in self.students:  # 检查学号是否存在
                print(f"\n查询结果：")
                print(self.students[student_id])  # 显示查询到的学生信息
            else:  # 如果学号不存在
                print("未找到该学号的学生。")
        
        elif choice == '2':  # 如果选择按姓名查询
            name = input("请输入姓名：").strip()  # 获取要查询的姓名
            results = [student for student in self.students.values() if name in student.name]  # 使用列表推导式查找包含指定姓名的学生
            self._display_search_results(results, "姓名")  # 调用方法显示查询结果
        
        elif choice == '3':  # 如果选择按班级查询
            class_name = input("请输入班级：").strip()  # 获取要查询的班级
            results = [student for student in self.students.values() if class_name in student.class_name]  # 使用列表推导式查找包含指定班级的学生
            self._display_search_results(results, "班级")  # 调用方法显示查询结果
        
        elif choice == '4':  # 如果选择按专业查询
            major = input("请输入专业：").strip()  # 获取要查询的专业
            results = [student for student in self.students.values() if major in student.major]  # 使用列表推导式查找包含指定专业的学生
            self._display_search_results(results, "专业")  # 调用方法显示查询结果
        
        else:  # 如果选择无效
            print("无效的选择！")
    
    def _display_search_results(self, results: List[Student], search_type: str):  # 定义私有方法显示查询结果，参数为结果列表和查询类型
        if results:  # 如果有查询结果
            print(f"\n按{search_type}查询结果（共{len(results)}条）：")
            for i, student in enumerate(results, 1):  # 遍历结果列表，enumerate从1开始编号
                print(f"{i}. {student}")  # 显示编号和学生信息
        else:  # 如果没有查询结果
            print(f"未找到匹配的学生。")
    
    def list_all_students(self):  # 定义显示所有学生方法，列出系统中的所有学生
        print("\n=== 所有学生列表 ===")
        if not self.students:  # 检查学生字典是否为空
            print("暂无学生数据。")
            return  # 如果为空则退出方法
        
        print(f"共有 {len(self.students)} 名学生：")
        for i, student in enumerate(self.students.values(), 1):  # 遍历所有学生，enumerate从1开始编号
            print(f"{i}. {student}")  # 显示编号和学生信息
    
    def add_award(self):  # 定义添加奖项方法，处理新奖项信息的录入
        print("\n=== 添加奖项 ===")
        award_id = input("请输入奖项ID：").strip()  # 获取用户输入的奖项ID并去除首尾空格
        
        if award_id in self.awards:  # 检查奖项ID是否已经存在
            print("该奖项ID已存在！")
            return  # 如果存在则退出方法
        
        name = input("请输入奖项名称：").strip()  # 获取用户输入的奖项名称并去除首尾空格
        print("请选择奖项级别：")
        print("1. 国家级")
        print("2. 省级")
        print("3. 校级")
        print("4. 院级")
        
        level_choice = input("请选择级别（1-4）：").strip()  # 获取用户选择的级别编号
        level_map = {'1': '国家级', '2': '省级', '3': '校级', '4': '院级'}  # 创建级别映射字典
        level = level_map.get(level_choice, '校级')  # 根据选择获取级别名称，默认为校级
        
        description = input("请输入奖项描述（可选）：").strip()  # 获取用户输入的奖项描述，可选项
        
        try:  # 使用try-except块处理可能的类型转换异常
            score = int(input("请输入奖项分数：").strip())  # 获取用户输入的分数并转换为整数
        except ValueError:  # 如果输入的不是有效数字
            score = 0  # 设置默认分数为0
        
        if not all([award_id, name]):  # 检查必填字段是否都有值
            print("奖项ID和名称不能为空！")
            return  # 如果有空值则退出方法
        
        award = Award(award_id, name, level, description, score)  # 创建新的奖项对象
        self.awards[award_id] = award  # 将奖项对象添加到系统的奖项字典中
        print(f"奖项 {name} 添加成功！")
        self.save_data()  # 保存数据到文件
    
    def delete_award(self):  # 定义删除奖项方法，处理奖项信息的删除
        print("\n=== 删除奖项 ===")
        award_id = input("请输入要删除的奖项ID：").strip()  # 获取用户输入的要删除的奖项ID
        
        if award_id not in self.awards:  # 检查奖项ID是否存在
            print("奖项ID不存在！")
            return  # 如果不存在则退出方法
        
        award = self.awards[award_id]  # 获取要删除的奖项对象
        confirm = input(f"确认删除奖项 {award.name}（{award_id}）？(y/n)：").strip().lower()  # 请求用户确认删除操作
        
        if confirm == 'y':  # 如果用户确认删除
            to_delete = [eid for eid, evaluation in self.evaluations.items() if evaluation.award_id == award_id]  # 找出所有与该奖项相关的评定记录
            for eid in to_delete:  # 遍历要删除的评定ID列表
                del self.evaluations[eid]  # 删除相关的评定记录，保持数据一致性
            
            del self.awards[award_id]  # 从奖项字典中删除该奖项
            print(f"奖项 {award.name} 删除成功！")
            self.save_data()  # 保存数据到文件
        else:  # 如果用户取消删除
            print("取消删除。")
    
    def update_award(self):  # 定义修改奖项信息方法，处理奖项信息的更新
        print("\n=== 修改奖项信息 ===")
        award_id = input("请输入要修改的奖项ID：").strip()  # 获取用户输入的要修改的奖项ID
        
        if award_id not in self.awards:  # 检查奖项ID是否存在
            print("奖项ID不存在！")
            return  # 如果不存在则退出方法
        
        award = self.awards[award_id]  # 获取要修改的奖项对象
        print(f"当前奖项信息：{award}")
        
        print("\n请输入新信息（直接回车保持原值）：")
        name = input(f"奖项名称（{award.name}）：").strip()  # 获取新的奖项名称，如果为空则保持原值
        
        print("请选择奖项级别：")
        print("1. 国家级")
        print("2. 省级")
        print("3. 校级")
        print("4. 院级")
        level_choice = input(f"级别（当前：{award.level}）：").strip()  # 获取新的级别选择
        level_map = {'1': '国家级', '2': '省级', '3': '校级', '4': '院级'}  # 创建级别映射字典
        level = level_map.get(level_choice, award.level)  # 根据选择获取级别名称，如果没有选择则保持原值
        
        description = input(f"描述（{award.description}）：").strip()  # 获取新的描述信息
        score_input = input(f"分数（{award.score}）：").strip()  # 获取新的分数输入
        
        if name:  # 如果输入了新的奖项名称
            award.name = name  # 更新奖项名称
        if level_choice:  # 如果选择了新的级别
            award.level = level  # 更新奖项级别
        if description or description == "":  # 如果输入了新的描述（包括空字符串）
            award.description = description  # 更新奖项描述
        if score_input:  # 如果输入了新的分数
            try:  # 使用try-except块处理可能的类型转换异常
                award.score = int(score_input)  # 将输入的分数转换为整数并更新
            except ValueError:  # 如果输入的不是有效数字
                print("分数必须为数字！")
        
        print("奖项信息修改成功！")
        self.save_data()  # 保存数据到文件
    
    def list_all_awards(self):  # 定义显示所有奖项方法，列出系统中的所有奖项
        print("\n=== 所有奖项列表 ===")
        if not self.awards:  # 检查奖项字典是否为空
            print("暂无奖项数据。")
            return  # 如果为空则退出方法
        
        print(f"共有 {len(self.awards)} 个奖项：")
        for i, award in enumerate(self.awards.values(), 1):  # 遍历所有奖项，enumerate从1开始编号
            print(f"{i}. {award}")  # 显示编号和奖项信息
    
    def add_evaluation(self):  # 定义添加评定方法，处理新评定记录的录入
        print("\n=== 添加评定 ===")
        eval_id = input("请输入评定ID：").strip()  # 获取用户输入的评定ID并去除首尾空格
        
        if eval_id in self.evaluations:  # 检查评定ID是否已经存在
            print("该评定ID已存在！")
            return  # 如果存在则退出方法
        
        student_id = input("请输入学生学号：").strip()  # 获取用户输入的学生学号
        if student_id not in self.students:  # 检查学生学号是否存在
            print("学生学号不存在！请先添加学生。")
            return  # 如果不存在则退出方法
        
        award_id = input("请输入奖项ID：").strip()  # 获取用户输入的奖项ID
        if award_id not in self.awards:  # 检查奖项ID是否存在
            print("奖项ID不存在！请先添加奖项。")
            return  # 如果不存在则退出方法
        
        eval_date = input("请输入评定日期（YYYY-MM-DD）：").strip()  # 获取用户输入的评定日期
        if not eval_date:  # 如果没有输入日期
            eval_date = datetime.now().strftime("%Y-%m-%d")  # 使用当前日期作为默认值
        
        evaluator = input("请输入评定人（可选）：").strip()  # 获取用户输入的评定人信息，可选项
        remarks = input("请输入备注（可选）：").strip()  # 获取用户输入的备注信息，可选项
        
        existing = [e for e in self.evaluations.values() 
                   if e.student_id == student_id and e.award_id == award_id]  # 使用列表推导式检查是否已存在相同的学生-奖项评定组合
        if existing:  # 如果已经存在相同的评定记录
            print("该学生已经有此奖项的评定记录！")
            return  # 退出方法，避免重复评定
        
        evaluation = Evaluation(eval_id, student_id, award_id, eval_date, evaluator, remarks)  # 创建新的评定对象
        self.evaluations[eval_id] = evaluation  # 将评定对象添加到系统的评定字典中
        
        student_name = self.students[student_id].name  # 获取学生姓名用于显示
        award_name = self.awards[award_id].name  # 获取奖项名称用于显示
        print(f"评定记录添加成功！学生：{student_name}，奖项：{award_name}")
        self.save_data()  # 保存数据到文件
    
    def delete_evaluation(self):  # 定义删除评定方法，处理评定记录的删除
        print("\n=== 删除评定 ===")
        eval_id = input("请输入要删除的评定ID：").strip()  # 获取用户输入的要删除的评定ID
        
        if eval_id not in self.evaluations:  # 检查评定ID是否存在
            print("评定ID不存在！")
            return  # 如果不存在则退出方法
        
        evaluation = self.evaluations[eval_id]  # 获取要删除的评定对象
        student_name = self.students.get(evaluation.student_id, {}).name if evaluation.student_id in self.students else "未知"  # 安全获取学生姓名，如果学生不存在或对象为空则显示"未知"
        award_name = self.awards.get(evaluation.award_id, {}).name if evaluation.award_id in self.awards else "未知"  # 安全获取奖项名称，如果奖项不存在或对象为空则显示"未知"
        
        confirm = input(f"确认删除评定记录？学生：{student_name}，奖项：{award_name} (y/n)：").strip().lower()  # 请求用户确认删除操作
        
        if confirm == 'y':  # 如果用户确认删除
            del self.evaluations[eval_id]  # 从评定字典中删除该评定记录
            print("评定记录删除成功！")
            self.save_data()  # 保存数据到文件
        else:  # 如果用户取消删除
            print("取消删除。")
    
    def list_all_evaluations(self):  # 定义显示所有评定方法，列出系统中的所有评定记录
        print("\n=== 所有评定列表 ===")
        if not self.evaluations:  # 检查评定字典是否为空
            print("暂无评定数据。")
            return  # 如果为空则退出方法
        
        print(f"共有 {len(self.evaluations)} 条评定记录：")
        for i, evaluation in enumerate(self.evaluations.values(), 1):  # 遍历所有评定记录，enumerate从1开始编号
            student_name = self.students.get(evaluation.student_id, {}).name if evaluation.student_id in self.students else "未知"  # 安全获取学生姓名
            award_name = self.awards.get(evaluation.award_id, {}).name if evaluation.award_id in self.awards else "未知"  # 安全获取奖项名称
            print(f"{i}. 评定ID：{evaluation.eval_id} | 学生：{student_name} | 奖项：{award_name} | 日期：{evaluation.eval_date}")  # 显示评定记录摘要信息
    
    def search_evaluations_by_student(self):  # 定义按学生查询评定方法，查询指定学生的所有评定记录
        print("\n=== 按学生查询评定 ===")
        student_id = input("请输入学生学号：").strip()  # 获取用户输入的学生学号
        
        if student_id not in self.students:  # 检查学生学号是否存在
            print("学生学号不存在！")
            return  # 如果不存在则退出方法
        
        student = self.students[student_id]  # 获取学生对象
        evaluations = [e for e in self.evaluations.values() if e.student_id == student_id]  # 使用列表推导式查找该学生的所有评定记录
        
        if evaluations:  # 如果找到评定记录
            print(f"\n学生 {student.name} 的所有评定记录（共{len(evaluations)}条）：")
            total_score = 0  # 初始化总分变量
            for i, evaluation in enumerate(evaluations, 1):  # 遍历评定记录，enumerate从1开始编号
                award = self.awards.get(evaluation.award_id)  # 获取对应的奖项对象
                award_name = award.name if award else "未知"  # 获取奖项名称，如果奖项不存在则显示"未知"
                award_score = award.score if award else 0  # 获取奖项分数，如果奖项不存在则为0
                total_score += award_score  # 累加到总分
                print(f"{i}. 奖项：{award_name} | 分数：{award_score} | 日期：{evaluation.eval_date}")  # 显示评定记录详情
            print(f"总分：{total_score}")
        else:  # 如果没有找到评定记录
            print(f"学生 {student.name} 暂无评定记录。")
    
    def show_statistics(self):  # 定义显示统计信息方法，展示系统的各种统计数据
        print("\n=== 系统统计信息 ===")
        print(f"学生总数：{len(self.students)}")
        print(f"奖项总数：{len(self.awards)}")
        print(f"评定总数：{len(self.evaluations)}")
        
        if self.awards:  # 如果系统中有奖项数据
            print("\n奖项级别统计：")
            level_count = {}  # 初始化级别计数字典
            for award in self.awards.values():  # 遍历所有奖项
                level_count[award.level] = level_count.get(award.level, 0) + 1  # 统计每个级别的奖项数量，使用get方法安全获取计数
            for level, count in level_count.items():  # 遍历级别计数字典
                print(f"  {level}：{count} 个")
        
        if self.evaluations:  # 如果系统中有评定数据
            print("\n获奖学生统计：")
            student_awards = {}  # 初始化学生获奖字典
            for evaluation in self.evaluations.values():  # 遍历所有评定记录
                if evaluation.student_id not in student_awards:  # 如果学生不在获奖字典中
                    student_awards[evaluation.student_id] = []  # 为该学生初始化空的奖项列表
                student_awards[evaluation.student_id].append(evaluation.award_id)  # 将奖项ID添加到该学生的奖项列表中
            
            print(f"获奖学生数：{len(student_awards)}")
            if student_awards:  # 如果有获奖学生
                max_awards = max(len(awards) for awards in student_awards.values())  # 找出获奖数量的最大值
                top_students = [sid for sid, awards in student_awards.items() if len(awards) == max_awards]  # 找出获奖数量等于最大值的所有学生
                
                print(f"最多获奖数：{max_awards}")
                print("获奖数最多的学生：")
                for sid in top_students:  # 遍历获奖最多的学生列表
                    student_name = self.students.get(sid, {}).name if sid in self.students else "未知"  # 安全获取学生姓名
                    print(f"  {student_name}（{sid}）：{max_awards} 个奖项")
    
    def export_student_report(self):  # 定义导出学生获奖报告方法，生成详细的学生获奖报告文件
        print("\n=== 导出学生获奖报告 ===")
        student_id = input("请输入学生学号：").strip()  # 获取用户输入的学生学号
        
        if student_id not in self.students:  # 检查学生学号是否存在
            print("学生学号不存在！")
            return  # 如果不存在则退出方法
        
        student = self.students[student_id]  # 获取学生对象
        evaluations = [e for e in self.evaluations.values() if e.student_id == student_id]  # 使用列表推导式获取该学生的所有评定记录
        
        filename = f"student_report_{student_id}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt"  # 生成带时间戳的报告文件名，避免文件名冲突
        
        try:  # 使用try-except块处理可能的文件操作异常
            with open(filename, 'w', encoding='utf-8') as f:  # 以写入模式打开文件，指定UTF-8编码
                f.write("=" * 50 + "\n")  # 写入分隔线
                f.write(f"学生获奖报告\n")  # 写入报告标题
                f.write("=" * 50 + "\n\n")  # 写入分隔线和空行
                
                f.write(f"学生信息：\n")  # 写入学生信息标题
                f.write(f"  学号：{student.student_id}\n")  # 写入学生学号
                f.write(f"  姓名：{student.name}\n")  # 写入学生姓名
                f.write(f"  班级：{student.class_name}\n")  # 写入学生班级
                f.write(f"  专业：{student.major}\n")  # 写入学生专业
                f.write(f"  电话：{student.phone}\n")  # 写入学生电话
                f.write(f"  邮箱：{student.email}\n\n")  # 写入学生邮箱和空行
                
                f.write(f"获奖记录：\n")  # 写入获奖记录标题
                if evaluations:  # 如果有评定记录
                    total_score = 0  # 初始化总分变量
                    for i, evaluation in enumerate(evaluations, 1):  # 遍历评定记录，enumerate从1开始编号
                        award = self.awards.get(evaluation.award_id)  # 获取对应的奖项对象
                        if award:  # 如果奖项对象存在
                            f.write(f"  {i}. {award.name}\n")  # 写入奖项名称
                            f.write(f"     级别：{award.level}\n")  # 写入奖项级别
                            f.write(f"     分数：{award.score}\n")  # 写入奖项分数
                            f.write(f"     获奖日期：{evaluation.eval_date}\n")  # 写入获奖日期
                            f.write(f"     评定人：{evaluation.evaluator}\n")  # 写入评定人
                            f.write(f"     备注：{evaluation.remarks}\n\n")  # 写入备注和空行
                            total_score += award.score  # 累加到总分
                    
                    f.write(f"获奖总数：{len(evaluations)}\n")  # 写入获奖总数
                    f.write(f"总分：{total_score}\n")  # 写入总分
                else:  # 如果没有评定记录
                    f.write("  暂无获奖记录\n")  # 写入无获奖记录提示
                
                f.write(f"\n报告生成时间：{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")  # 写入报告生成时间
                f.write("=" * 50 + "\n")  # 写入分隔线
            
            print(f"学生获奖报告已导出到文件：{filename}")
        
        except Exception as e:  # 捕获所有异常
            print(f"报告导出失败：{e}")
    
    def run(self):  # 定义运行方法，启动系统主循环
        print("欢迎使用学生奖评系统！")
        
        while True:  # 无限循环，直到用户选择退出
            self.show_main_menu()  # 显示主菜单
            choice = input("\n请选择功能：").strip()  # 获取用户选择的功能
            
            if choice == '1':  # 如果选择学生管理
                self.student_management()  # 调用学生管理方法
            elif choice == '2':  # 如果选择奖项管理
                self.award_management()  # 调用奖项管理方法
            elif choice == '3':  # 如果选择评定管理
                self.evaluation_management()  # 调用评定管理方法
            elif choice == '4':  # 如果选择统计查询
                self.statistics_management()  # 调用统计查询方法
            elif choice == '5':  # 如果选择保存数据
                self.save_data()  # 调用保存数据方法
            elif choice == '0':  # 如果选择退出系统
                print("感谢使用学生奖评系统！再见！")
                self.save_data()  # 在退出前保存数据
                break  # 跳出循环，结束程序
            else:  # 如果选择无效
                print("无效的选择，请重新输入！")
    
    def show_main_menu(self):  # 定义显示主菜单方法，展示系统的主要功能选项
        print("\n" + "=" * 40)
        print("学生奖评系统 - 主菜单")
        print("=" * 40)
        print("1. 学生管理")
        print("2. 奖项管理")
        print("3. 评定管理")
        print("4. 统计查询")
        print("5. 保存数据")
        print("0. 退出系统")
        print("=" * 40)
    
    def student_management(self):  # 定义学生管理方法，提供学生相关的所有操作菜单
        while True:  # 无限循环，直到用户选择返回主菜单
            print("\n" + "-" * 30)
            print("学生管理")
            print("-" * 30)
            print("1. 添加学生")
            print("2. 删除学生")
            print("3. 修改学生")
            print("4. 查询学生")
            print("5. 显示所有学生")
            print("0. 返回主菜单")
            print("-" * 30)
            
            choice = input("请选择功能：").strip()  # 获取用户选择的功能
            
            if choice == '1':  # 如果选择添加学生
                self.add_student()  # 调用添加学生方法
            elif choice == '2':  # 如果选择删除学生
                self.delete_student()  # 调用删除学生方法
            elif choice == '3':  # 如果选择修改学生
                self.update_student()  # 调用修改学生方法
            elif choice == '4':  # 如果选择查询学生
                self.search_student()  # 调用查询学生方法
            elif choice == '5':  # 如果选择显示所有学生
                self.list_all_students()  # 调用显示所有学生方法
            elif choice == '0':  # 如果选择返回主菜单
                break  # 跳出循环，返回主菜单
            else:  # 如果选择无效
                print("无效的选择，请重新输入！")
    
    def award_management(self):  # 定义奖项管理方法，提供奖项相关的所有操作菜单
        while True:  # 无限循环，直到用户选择返回主菜单
            print("\n" + "-" * 30)
            print("奖项管理")
            print("-" * 30)
            print("1. 添加奖项")
            print("2. 删除奖项")
            print("3. 修改奖项")
            print("4. 显示所有奖项")
            print("0. 返回主菜单")
            print("-" * 30)
            
            choice = input("请选择功能：").strip()  # 获取用户选择的功能
            
            if choice == '1':  # 如果选择添加奖项
                self.add_award()  # 调用添加奖项方法
            elif choice == '2':  # 如果选择删除奖项
                self.delete_award()  # 调用删除奖项方法
            elif choice == '3':  # 如果选择修改奖项
                self.update_award()  # 调用修改奖项方法
            elif choice == '4':  # 如果选择显示所有奖项
                self.list_all_awards()  # 调用显示所有奖项方法
            elif choice == '0':  # 如果选择返回主菜单
                break  # 跳出循环，返回主菜单
            else:  # 如果选择无效
                print("无效的选择，请重新输入！")
    
    def evaluation_management(self):  # 定义评定管理方法，提供评定相关的所有操作菜单
        while True:  # 无限循环，直到用户选择返回主菜单
            print("\n" + "-" * 30)
            print("评定管理")
            print("-" * 30)
            print("1. 添加评定")
            print("2. 删除评定")
            print("3. 显示所有评定")
            print("4. 按学生查询评定")
            print("0. 返回主菜单")
            print("-" * 30)
            
            choice = input("请选择功能：").strip()  # 获取用户选择的功能
            
            if choice == '1':  # 如果选择添加评定
                self.add_evaluation()  # 调用添加评定方法
            elif choice == '2':  # 如果选择删除评定
                self.delete_evaluation()  # 调用删除评定方法
            elif choice == '3':  # 如果选择显示所有评定
                self.list_all_evaluations()  # 调用显示所有评定方法
            elif choice == '4':  # 如果选择按学生查询评定
                self.search_evaluations_by_student()  # 调用按学生查询评定方法
            elif choice == '0':  # 如果选择返回主菜单
                break  # 跳出循环，返回主菜单
            else:  # 如果选择无效
                print("无效的选择，请重新输入！")
    
    def statistics_management(self):  # 定义统计查询方法，提供统计和查询相关的所有操作菜单
        while True:  # 无限循环，直到用户选择返回主菜单
            print("\n" + "-" * 30)
            print("统计查询")
            print("-" * 30)
            print("1. 系统统计信息")
            print("2. 导出学生获奖报告")
            print("0. 返回主菜单")
            print("-" * 30)
            
            choice = input("请选择功能：").strip()  # 获取用户选择的功能
            
            if choice == '1':  # 如果选择系统统计信息
                self.show_statistics()  # 调用显示统计信息方法
            elif choice == '2':  # 如果选择导出学生获奖报告
                self.export_student_report()  # 调用导出学生获奖报告方法
            elif choice == '0':  # 如果选择返回主菜单
                break  # 跳出循环，返回主菜单
            else:  # 如果选择无效
                print("无效的选择，请重新输入！")

def main():  # 定义主函数，程序的入口点
    try:  # 使用try-except块处理可能的异常
        system = StudentAwardSystem()  # 创建学生奖评系统实例
        system.run()  # 运行系统主循环
    except KeyboardInterrupt:  # 捕获用户中断异常（Ctrl+C）
        print("\n\n程序被用户中断，正在保存数据...")
        try:  # 尝试保存数据
            system.save_data()  # 调用保存数据方法
        except:  # 如果保存失败也不抛出异常
            pass  # 忽略保存失败的异常
        print("数据保存完成，程序退出。")
    except Exception as e:  # 捕获其他所有异常
        print(f"程序运行出错：{e}")

if __name__ == "__main__":  # 检查是否为主程序运行（而不是被导入）
    main()  # 调用主函数启动程序
